home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / text / edit / BareED.lha / BareED / DAC / source / Dump.c < prev    next >
C/C++ Source or Header  |  2001-03-21  |  32KB  |  946 lines

  1. /*
  2.     Copyright March 2001 J.v.d.Loo
  3.  
  4.     Treat  this  source  code and the load file based on this source as Freeware - I would say Public
  5.     Domain  when this wouldn't give other people the right to add their copyright signs - which among
  6.     other things can mean that the files Dump and Dump.c cannot be used freely...
  7.  
  8.     Start over:
  9.     This  file  is  not  meant as lesson how to use the "printer device" but as an example how to use
  10.     the (poor) DAC interface of BareED.
  11.  
  12.     Note:    Any DAC-application will be started from BareED!
  13.             A   DAC-application   will   get  a  normal  Workbench-start-up-message  with  additional
  14.             information and functions that it may use.
  15.             A  DAC-aaplication  may  be  written  as  base-relative  (small  code/data)  or  as large
  16.             code/data  model  - it doesn't matter. The base register A4 of your program is remembered
  17.             and restored by BareED!
  18.             ->  NOTE: Traditionally register A5 is used by the E-compiler - but currently BareED does
  19.                       not care about it - sorry.
  20.             If  a  CallBack-Hook  function of a DAC-application is called back you have to restore on
  21.             exit all registers to their initial state, except D0-D1, A0-A1, A4.
  22.  
  23.             Note well:    BareED  is  locked,  better  said:  protected  against modifications from the
  24.                         outside  (non-DAC-applications),  which means that the archive cannot be gone
  25.                         or  changed  when  there  is  still  at  least  one  DAC-application  alive -
  26.                         exception:  a  marked  block!!!  But the addresses of BlockStart and BlockEnd
  27.                         are still valid although the user could have already dismarked this block!
  28.  
  29.             Additional note:
  30.                         I  have  used  standard  Bitplanes and Bitmaps in this example although a 3rd
  31.                         party  graphic  board  software  could  be running and therewith non-standard
  32.                         Bitplanes  and Bitmaps (when used) would be more effective. But this requires
  33.                         on  OS  3.0  and 3.1 a patched "printer.device". As far as I know the OSs 3.5
  34.                         and 3.9 support non-standard Bitmaps native.
  35.  
  36.             Used printer by author:
  37.                         Since  I  found no "printer driver" for my Canon BJC 2000 printer, I've freed
  38.                         from  dust my old Epson LQ 400 printer and used it. Because the EpsonQ driver
  39.                         does  not compute page sizes correctly (2804 dots in horizontal and 0 dots in
  40.                         vertical  direction) I wrote a new "printer driver" called EpsonLQ that fixes
  41.                         these  and  other  bugs (now it supports also the Euro-sign). Since the Epson
  42.                         LQ  400 printer has only 180 dpi in vertical direction, the result of Dump is
  43.                         poor. Perhaps with a better printer (device ?) the result of Dump is better.
  44.  
  45.             Help needed:
  46.                         If  you  know  how  to apply "anti-alias" to a given font (or how to render a
  47.                         font  so  that  a  "anti-alias" text can be performed) give me a hint. If you
  48.                         already  managed  to complete a useable routine please send it to me for free
  49.                         (email M.Berson in this case: BersonM@aol.com).
  50. */
  51.  
  52.  
  53. #include <exec/memory.h>
  54. #include <exec/libraries.h>
  55. #include <exec/ports.h>
  56.  
  57. #include <dos/dos.h>
  58.  
  59. #include <intuition/intuition.h>
  60. #include <intuition/screens.h>
  61. #include <intuition/preferences.h>
  62.  
  63. #include <graphics/gfxbase.h>
  64. #include <graphics/gfx.h>
  65. #include <graphics/displayinfo.h>
  66. #include <graphics/rastport.h>
  67. #include <graphics/text.h>
  68.  
  69. #include <libraries/locale.h>
  70.  
  71. #include <workbench/startup.h>
  72.  
  73. #include <devices/printer.h>
  74. #include <devices/prtbase.h>
  75.  
  76. #include <devices/printer.h>
  77. #include <devices/prtbase.h>
  78.  
  79. #include <clib/exec_protos.h>
  80. #include <clib/graphics_protos.h>
  81. #include <clib/intuition_protos.h>
  82. #include <clib/locale_protos.h>
  83. #include <clib/alib_protos.h>
  84. #include <clib/alib_stdio_protos.h>
  85.  
  86. #if !defined(__MAXON__) && !defined(__STORM__)
  87. #include <proto/exec.h>
  88. #include <proto/graphics.h>
  89. #include <proto/intuition.h>
  90. #include <proto/gadtools.h>
  91. #include <proto/locale.h>
  92. #else
  93. #include <pragma/exec_lib.h>
  94. #include <pragma/graphics_lib.h>
  95. #include <pragma/intuition_lib.h>
  96. #include <pragma/gadtools_lib.h>
  97. #include <pragma/locale_lib.h>
  98. #endif
  99.  
  100. #include <string.h>
  101.  
  102. #if defined(__MAXON__)                            /* ... enable Workbench start */
  103. struct WBStartup *WBenchMsg = NULL;                /* Variable */
  104. extern "C" void wbparse( struct WBStartup *);    /* Prototype */
  105. extern "C" void wbmain( struct WBStartup *ws)    /* This is called if we're running from WB */
  106. {
  107.     WBenchMsg = ws; /* Remember message */
  108.     wbparse( ws);    /* Parse WBench arguments (argv[0....])*/
  109. }
  110. #endif
  111.  
  112. /* Macro by G. Nikl */
  113. #if defined(__GNUC__)
  114.  #define ASM
  115.  #define REG(reg,arg) arg __asm(#reg)
  116. #else
  117.  #if !defined(__MAXON__) 
  118.   #define ASM __asm
  119.  #else
  120.   #define ASM
  121.   #define __saveds
  122.  #endif
  123.  #define REG(reg,arg) register __##reg arg
  124. #endif
  125.  
  126.  
  127. unsigned char VerStr[] = "$VER: DAC_Dump 21.9 (21-Mar-01)";
  128.  
  129.  
  130. union PrinterIO
  131. {
  132.     struct IOStdReq    IoStd;
  133.     struct IODRPReq    IoDpRP;
  134.     struct IOPrtCmdReq IoPrtCom;
  135. };
  136.  
  137.  
  138. /* Possible printer.device and I/O errors */
  139. STRPTR ErrorText[] =
  140. {
  141.     "\000\x0ANo error",
  142.     "\000\x0BPrinting-progress aborted",
  143.     "\000\x0CNot a graphic printer",
  144.     "\000\x0DHAM image cannot be converted",        /* Cannot occur */
  145.     "\000\x0EToo large region to dump",
  146.     "\000\x0FOut of supported dimension",            /* Cannot occur */
  147.     "\000\x10Not enough memory",
  148.     "\000\x11Not enough memory for print-buffer",
  149.     "\000\x12IO: Open device failed",
  150.     "\000\x13IO: Printing-progress aborted",
  151.     "\000\x14IO: Unsupported command",
  152.     "\000\x15IO: Command length did not match"
  153. };
  154.  
  155. struct PseudoMsg
  156. {
  157.     struct WBStartup      pm_Startup;            /* Only readable! */
  158.     BPTR                 pm_Lock;                /* Hands off! */
  159.     unsigned char        *pm_Name;                /* Hands off! */
  160.     unsigned char         pm_FileName[108];        /* Hands off! */
  161.     unsigned char         pm_Dir[256];            /* Hands off! */
  162.     struct GfxBase        *pm_GfxBase;            /* At least v33 */
  163.     struct IntuitionBase *pm_IntuitionBase;        /* At least v36 */
  164.     struct Library        *pm_GadToolsBase;        /* At least v36 */
  165.     struct Library        *pm_DiskfontBase;        /* At least v33 */
  166.     struct Library        *pm_AslBase;            /* At least v38 */
  167.     struct Library        *pm_IconBase;            /* At least v33 */
  168.     struct Library        *pm_LocaleBase;            /* At least v1 */
  169.     struct Library        *pm_WorkbenchBase;        /* At least v36 */
  170.     void                *VisualInfo;            /* Never release it! */
  171.     struct DrawInfo        *DrawInfo;                /* Never release it! */
  172.     unsigned char        *pm_RegionStart;
  173.     unsigned int         pm_RegionSize;
  174.     unsigned char        *pm_TextStart;
  175.     unsigned char        *pm_TextEnd;
  176.     unsigned char        *pm_BlockStart;
  177.     unsigned char        *pm_BlockEnd;
  178.     struct TextAttr        *pm_FontAttr;
  179.     struct TextFont        *pm_Font;
  180.     struct Window        *pm_EdWindow;
  181.     unsigned int         pm_TabWidth;            /* In pixels */
  182.     unsigned int         pm_TabStops;            /* A tap stop occurs every 'n' */
  183.     unsigned int         pm_RightMargin;
  184.     unsigned char        *pm_CharSpace;            /* Pointer to the character-spaces of the used font */
  185.     void                (*pm_GetAttr)( struct TagItem *taglist);        /* Currently NULL (out of order!) */
  186.     void                (*pm_ChangeAttr)( struct TagItem *taglist);        /* Currently NULL (out of order!) */
  187.     void                (*pm_BlockInput)( void);
  188.     void                (*pm_AllowInput)( void);
  189.     void                (*pm_Tell)( STRPTR str);
  190.     unsigned int        (*pm_CaseTell)( STRPTR str);
  191.     unsigned int        (*pm_RequestNumber)( unsigned int initial, STRPTR winname, STRPTR hailtext,\
  192.                                              STRPTR gadtext, BOOL zero);
  193.     unsigned int        (*pm_StrPixelLen)( unsigned char *start, unsigned char *end);
  194.     void                (*pm_DumpStrLine)( unsigned char *start, unsigned char *end, struct RastPort *rp,\
  195.                                            unsigned int x, unsigned int y);
  196.     unsigned int        (*pm_WidestStrLen)( unsigned char *text, unsigned char *stop,\
  197.                                             unsigned int (*inform_code)( unsigned int len, unsigned int line),\
  198.                                             unsigned int inform);
  199.     void                (*pm_DumpStrings)( struct RastPort *rp,\
  200.                                            unsigned int (*dump_code)( unsigned int len, unsigned int line),\
  201.                                            unsigned char *text, unsigned char *stop);
  202.     void                (*pm_FreeProgressBar)( struct ProgressBar *pb);
  203.     struct ProgressBar *(*pm_CreateProgressBar)( STRPTR wintitle, STRPTR hail, STRPTR stop, STRPTR cont, STRPTR cancel);
  204.     unsigned int        (*pm_PullPBarEvent)( struct ProgressBar *pb);
  205.     void                (*pm_ChangePBarIndicator)( struct ProgressBar *pb, unsigned int percent, STRPTR hail);
  206. /* Following does not yet work properly - so don't use! */
  207.     void                (*pm_TogglePBarGad)( struct ProgressBar *pb);
  208. };
  209.  
  210.  
  211. struct IntuitionBase *IntuitionBase;
  212. struct GfxBase *GfxBase;
  213. struct Library *LocaleBase;
  214. struct Library *GadToolsBase;
  215.  
  216. struct Catalog *Cat;
  217.  
  218. struct MsgPort    *PrinterPort;
  219. union  PrinterIO *PIO;
  220. struct PrinterData *PD;
  221. struct PrinterExtendedData *PED;
  222.  
  223. struct PseudoMsg *PsMsg;    /* Message got from BareED */
  224.  
  225. struct ProgressBar            /* Don't use other items than this one of the ProgressBar... */
  226. {
  227.     struct Window *pb_Window;
  228. };    /* Don't rely on this end... */
  229.  
  230. struct ProgressBar *PB;        /* Will be created */
  231.  
  232. struct RastPort *FakeRP;
  233. struct BitMap *FakeBM;
  234. struct ColorMap *CM;
  235.  
  236. /* Since "printer device" destroys them, I have to remember them! */
  237. unsigned int DestHDots, DestVDots, ModeID;
  238. unsigned int VDotsPage, VDotsLine, HDotsLine, Lines;
  239.  
  240. /* Want to show user how much alredy worked out... */
  241. unsigned int Lines2Dump;    /* Amount total lines in printout */
  242.  
  243. #define TEXTBUFFERSIZE 256    /* Storage size (buffer) for strings */
  244. STRPTR TextBuffer;
  245.  
  246. BOOL Continue = TRUE;        /* While Continue is TRUE we continue - when FALSE, we quit */
  247.  
  248. /* Offset on paper and keep track of actual line dumped */
  249. unsigned CurrYdot, CurrLine;
  250.  
  251.  
  252. /* ---------------------------------------------------------------------
  253.     I don't want to waste memory so I use an own made sprintf() function
  254.     which is much shorter (it doesn't support floats and word descriptions)
  255.     than the original!
  256. */
  257.  
  258. void funny_code( REG(a3, volatile char *buf), REG(d0, volatile char c) )
  259. {
  260.     *buf++ = c;    /* move.b d0,(a3)+ */
  261. }                /* rts */
  262.  
  263. #define FUNC (void (*)()) &funny_code    /* Code should use: lea funny_code(An),a2 */
  264.  
  265. void SPrintf( char *buf, char *descr, ...)
  266. {
  267.     char *args;
  268.  
  269.     (char *) args = (char *) &descr;    /* Address format string on stack */
  270.     args += 4;                            /* Address 1st additional argument */
  271.     RawDoFmt( descr, args, FUNC, buf);
  272. }
  273.  
  274. /* -----------------------
  275.     Multilingual stuff...
  276.  
  277.     NOTE: I prepared the strings so that they contain a leading word, which is set up as follow:
  278.           1st byte (an octal number)
  279.           2nd byte (an octal or hexadecimal number)
  280.           3rd byte - string start
  281.           The  first two bytes (= one word) will be converted by GStr() to a longword - used as index
  282.           in the catalogue.
  283.  
  284.           By the way:  Several compilers have got problems with characters entered behind a backslash
  285.                        (when it is also a valid format descriptor, e.g. »E« !) - so watch out!
  286.  
  287. */
  288.  
  289. void OpenTheCatalog()
  290. {
  291.     Cat = (struct Catalog *) OpenCatalogA( 0, "dac_dump.catalog", 0);
  292. }
  293.  
  294. void CloseTheCatalog()
  295. {
  296.     if (Cat)
  297.         CloseCatalog( Cat);
  298. }
  299.  
  300. char * GStr( char *str)
  301. {
  302.     ULONG no;
  303.     char *rstr;
  304.  
  305.     no     = 0;
  306.     no     = ( (UBYTE) str[0] << 8) + (UBYTE) str[1];    /* Convert the two leading bytes of string into longword */
  307.     rstr = &str[2];                                    /* String's start */
  308.  
  309.     if (Cat)
  310.         rstr = (char *) GetCatalogStr( Cat, no, rstr);    /* Get string or the default... */
  311.  
  312.     return rstr;
  313. }
  314.  
  315.  
  316. /* ---------------------------------
  317.     CallBack Hook for WidestStrLen()
  318.  
  319.     No need here to save / load base register! - already done!
  320.  
  321.     Inform user if a line exeeds the computed limit. Routine
  322.     called from the inside of WidestStrLen() !
  323. */
  324.  
  325. unsigned int InformCode( unsigned int len, unsigned int line)
  326. {
  327.     unsigned int limit;
  328.  
  329.     limit = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  330.  
  331.     SPrintf( TextBuffer, GStr( "\001\001Line %ld exceeds with %ld pixels limit of %ld pixels!\n\n"\
  332.                                "Continue anyhow?"), line, len, limit);
  333.     Continue = PsMsg->pm_CaseTell( TextBuffer);
  334.  
  335.     return Continue;
  336. }
  337.  
  338.  
  339. /* --------------------------------
  340.     CallBack Hook for DumpStrings()
  341.  
  342.     No need here to save / load base register! - already done!
  343.  
  344.     This routine is called from DumpStrings() - when DumpStrings()
  345.     has layed out a new line - thus we can here dump the Raster Port
  346.     contents to the printer. Meanwhile we check for user actions -
  347.     like pause, continue or abandon the printout. 
  348. */
  349.  
  350. unsigned int DumpCode( unsigned int len, unsigned int line)
  351. {
  352.     BOOL cont = TRUE;
  353.     unsigned int signal, sigPrt, sigWd, id, spec, flag, percent, loop;
  354.     int i;
  355.  
  356.     /* Check if the dump will need a new page */
  357.     if ( VDotsPage < CurrYdot + VDotsLine)    /* Fits this line onto paper? */
  358.     {
  359.         /* Remember both - to set them later on! */
  360.         spec = PIO->IoDpRP.io_Special;
  361.         flag = PIO->IoDpRP.io_Flags;
  362.  
  363.         PIO->IoStd.io_Flags = IOF_QUICK;    /* Need no reply from "printer.device" */
  364.         PIO->IoStd.io_Command = CMD_WRITE;
  365.         PIO->IoStd.io_Length = 1;
  366.         PIO->IoStd.io_Data = "\014";        /* Eject page (12 = FormFeed) */
  367.  
  368.         WaitIO(  (struct IORequest *) PIO);    /* Wait until line has been dumped */
  369.         if ( DoIO( (struct IORequest *) PIO))
  370.             cont = PsMsg->pm_CaseTell( GStr( "\000\x16\Error occurred while ejecting the page!\n\n"\
  371.                                              "Continue anyway?") );
  372.  
  373.         /* Re-do for graphic dump */
  374.         PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  375.         PIO->IoDpRP.io_Flags = flag;
  376.         PIO->IoDpRP.io_RastPort = FakeRP;
  377.         PIO->IoDpRP.io_ColorMap = CM;
  378.         PIO->IoDpRP.io_Modes = ModeID;
  379.         PIO->IoDpRP.io_SrcX = 0;
  380.         PIO->IoDpRP.io_SrcY = 0;
  381.         PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  382.         PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  383.         PIO->IoDpRP.io_Special = spec;
  384.         PIO->IoDpRP.io_DestCols = DestHDots;
  385.         PIO->IoDpRP.io_DestRows = DestVDots;
  386.  
  387.         CurrYdot = 0;    /* Set to top of page */
  388.     }
  389.  
  390.     if (cont == TRUE)
  391.     {
  392.         /* Send to printer... */
  393.         WaitIO( (struct IORequest *) PIO);    /* Wait for last action to be completed */
  394.         SendIO( (struct IORequest *) PIO);    /* Attempt to dump Raster Port */
  395.         CurrYdot += VDotsLine;                /* Next offset (plus full line) */
  396.         CurrLine ++;                        /* One more line dumped */
  397.  
  398.         /* In case the progress-bar is accessible... */
  399.         if (PB)
  400.         {
  401.             percent = CurrLine * 100 / Lines2Dump;    /* How much in percent already worked out? */
  402.             SPrintf( TextBuffer, GStr( "\000\x46Printout completed to %ld%% "), percent);
  403.             PsMsg->pm_ChangePBarIndicator( PB, percent, TextBuffer);
  404.         }
  405.  
  406.         /* The following construct emulates the WaitIO() function but gives us
  407.            also the chance to set and wait for other, non "printer device" related
  408.            things, here break signal (CTRL-C) and progress-bar message
  409.         */
  410.         sigPrt = 1 << PrinterPort->mp_SigBit;                    /* Signal-bitmask of printer */
  411.         if (PB)
  412.             sigWd  = 1 << PB->pb_Window->UserPort->mp_SigBit;    /* and ditto for progress-bar */
  413.                 else
  414.             sigWd = 0;
  415.         signal = Wait( SIGBREAKF_CTRL_C | sigPrt | sigWd );        /* Cheap sleep! */
  416.  
  417.  
  418.         /* Break signal from the outside (system monitor) ? */
  419.         if ( (signal & SIGBREAKF_CTRL_C) )
  420.         {
  421.             AbortIO( (struct IORequest *) PIO);
  422.             WaitIO( (struct IORequest *) PIO);    /* Convention */
  423.             PsMsg->pm_Tell( GStr ("\000\x17Printing abandoned by user!") );
  424.             cont = FALSE;
  425.         }
  426.  
  427.  
  428.         /* Message from "printer device" ? */
  429.         if (cont == TRUE)
  430.         {
  431.             if ( (signal & sigPrt) )
  432.                 while ( GetMsg( PrinterPort));    /* Remove only the message */
  433.  
  434.             /* Check for error */
  435.             if (PIO->IoDpRP.io_Error)
  436.             {
  437.                 i = PIO->IoDpRP.io_Error;
  438.                 if (i < 0)                    /* IO error ? */
  439.                     i = i * -1 + 7;            /* Map to offset in table */
  440.                 SPrintf( TextBuffer, GStr( "\000\x18\Error: %s"), GStr( ErrorText[i]) );
  441.                 PsMsg->pm_Tell( TextBuffer);                                    
  442.                 cont = FALSE;
  443.             }
  444.         }
  445.  
  446.  
  447.         /* Progress-bar message? */
  448.         if (cont == TRUE)
  449.         {
  450.             if ( (signal & sigWd) )
  451.             {
  452.                 id = PsMsg->pm_PullPBarEvent( PB);    /* Get id of gadget clicked */
  453.  
  454.                 /* Pause? */
  455.                 if (id == 2)
  456.                 {
  457.                     spec = PIO->IoDpRP.io_Special;        /* Remember current state */
  458.                     flag = PIO->IoDpRP.io_Flags;
  459.  
  460.                     WaitIO( (struct IORequest *) PIO);    /* Wait for dump in progress to be completed */
  461.                     PIO->IoStd.io_Flags = IOF_QUICK;    /* Need no reply */
  462.                     PIO->IoStd.io_Command = CMD_STOP;    /* Stop dump (already completed but necessary) */
  463.                     DoIO( (struct IORequest *) PIO);    /* Do it now! */
  464.  
  465.                     loop = TRUE;
  466.                     while (loop)
  467.                     {
  468.                         signal = Wait( SIGBREAKF_CTRL_C | sigPrt | sigWd);
  469.                     
  470.                         /* A break signal from the outside? */
  471.                         if (signal & SIGBREAKF_CTRL_C)
  472.                         {
  473.                             AbortIO( (struct IORequest *) PIO);
  474.                             WaitIO( (struct IORequest *) PIO);    /* Convention */
  475.                             PsMsg->pm_Tell( GStr ("\000\x17Printing abandoned by user!") );
  476.                             cont = FALSE;
  477.                             loop = FALSE;
  478.                         }
  479.  
  480.  
  481.                         if (cont && loop)
  482.                         {
  483.                             /* Message from device? - can only be "stopped"! */
  484.                             if ( (signal & sigPrt) )
  485.                                 while ( GetMsg( PrinterPort));    /* Remove only the message */
  486.  
  487.                             /* Check for error */
  488.                             if (PIO->IoDpRP.io_Error)
  489.                             {
  490.                                 i = PIO->IoDpRP.io_Error;
  491.                                 if (i < 0)                    /* IO error ? */
  492.                                     i = i * -1 + 7;            /* Map to offset in table */
  493.                                 SPrintf( TextBuffer, GStr( "\000\x18\Error: %s"), GStr( ErrorText[i]) );
  494.                                 PsMsg->pm_Tell( TextBuffer);                                    
  495.                                 cont = FALSE;
  496.                                 loop = FALSE;
  497.                             }
  498.                         }
  499.  
  500.  
  501.                         /* Message from progress-bar? - note: we're paused! */
  502.                         if ( loop && (signal & sigWd) )
  503.                         {
  504.                             id = PsMsg->pm_PullPBarEvent( PB);    /* Get id of gadget clicked */
  505.  
  506.                             if (id == 2)    /* awake? */
  507.                             {
  508.                                 PIO->IoStd.io_Flags = IOF_QUICK;
  509.                                 PIO->IoStd.io_Command = CMD_START;    /* Continue dump (i.e. tell device we're */
  510.                                 DoIO( (struct IORequest *) PIO);    /* going to re-use it */
  511.  
  512.                                 /* Re-do for graphic dump */
  513.                                 PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  514.                                 PIO->IoDpRP.io_Flags = flag;
  515.                                 PIO->IoDpRP.io_RastPort = FakeRP;
  516.                                 PIO->IoDpRP.io_ColorMap = CM;
  517.                                 PIO->IoDpRP.io_Modes = ModeID;
  518.                                 PIO->IoDpRP.io_SrcX = 0;
  519.                                 PIO->IoDpRP.io_SrcY = 0;
  520.                                 PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  521.                                 PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  522.                                 PIO->IoDpRP.io_Special = spec;
  523.                                 PIO->IoDpRP.io_DestCols = DestHDots;
  524.                                 PIO->IoDpRP.io_DestRows = DestVDots;
  525.                                 loop = FALSE;
  526.                             }
  527.                             else
  528.                             {
  529.                                 if (id == 1)    /* Shame on user, firstly paused now abandoned... */
  530.                                 {
  531.                                     AbortIO( (struct IORequest *) PIO);
  532.                                     WaitIO( (struct IORequest *) PIO);
  533.                                     PsMsg->pm_Tell( GStr ("\000\x17Printing abandoned by user!") );
  534.                                     cont = FALSE;
  535.                                     loop = FALSE;
  536.                                 }
  537.                             }
  538.                         }
  539.                     }
  540.                 }
  541.                 else
  542.                 {
  543.                     /* User said stop and quit? */
  544.                     if (id == 1)
  545.                     {
  546.                         AbortIO( (struct IORequest *) PIO);
  547.                         WaitIO( (struct IORequest *) PIO);
  548.                         PsMsg->pm_Tell( GStr ("\000\x17Printing abandoned by user!") );
  549.                         cont = FALSE;
  550.                     }
  551.                 }
  552.             }
  553.         }    /* End progress-bar message */
  554.  
  555.  
  556.         /* Firstly, clear the complete bit-plane(s) */
  557.         SetDrMd( FakeRP, JAM2);        /* We want to overwrite */
  558.         SetAPen( FakeRP, 0);        /* Background pen */
  559.         RectFill( FakeRP, 0, 0, FakeBM->BytesPerRow * 8 - 1, FakeBM->Rows - 1);
  560.  
  561.         /* Set render pen - to make the characters visible */
  562.         SetAPen( FakeRP, 1);        /* Foreground pen */
  563.     }
  564.  
  565.     return cont;
  566. }
  567.  
  568. /* ----------------------------------------------------
  569.     Try to dump the specified characters to the printer
  570.  
  571.     Called with the widest string length in pixels.
  572.  
  573.     NOTE:
  574.         The 'FakeBM->Depth' must have already been set to the required depth -
  575.         in this example it was set to one (monochrome).
  576. */
  577.  
  578. void DoTheDump( unsigned int mustHave)
  579. {
  580.     unsigned int i, a, r, p;
  581.     unsigned char *curr, *end;
  582.  
  583.     a = mustHave / PsMsg->pm_CharSpace[ (UBYTE) ' '];
  584.  
  585.     if (PsMsg->pm_RightMargin < a)
  586.         i = PsMsg->pm_CaseTell( GStr( "\001\002Sure to continue with printout\n"\
  587.                                       "although not all characters fit onto concerned page?\n"\
  588.                                       "(Some beyond right margin - non-printable!)\n\n"\
  589.                                       "Continue?") );
  590.     if (i)
  591.     {
  592.         /* Compute size in bytes for bit-plane allocation */
  593.         i = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];    /* Size in pixels */
  594.         i = (i + 15) & -16;            /* 16-bit boundary */
  595.         i /= 8;                        /* ...in bytes */
  596.         FakeBM->BytesPerRow = i;    /* Amount of rows */
  597.  
  598.         FakeBM->Rows = PsMsg->pm_Font->tf_YSize + 1;
  599.  
  600.         if (GfxBase->LibNode.lib_Version <= 38 \
  601.             || (GetBitMapAttr( PsMsg->pm_EdWindow->WScreen->RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD))
  602.         {
  603.             /* Standard (PLANAR) display - so the bitplanes must reside in CHIP-RAM -
  604.                for the rendering functions
  605.             */
  606.             FakeBM->Planes[0] = (PLANEPTR) AllocMem( FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth, \
  607.                                                      MEMF_CLEAR|MEMF_CHIP)
  608.         }
  609.         else
  610.         {
  611.             /* There is a non-standard Bitmap - so I guess rendering to FAST-RAM will work! */
  612.             FakeBM->Planes[0] = (PLANEPTR) AllocMem( FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth, MEMF_CLEAR);
  613.         }
  614.  
  615.         /* Bitplane(s) allocated? */
  616.         if ( FakeBM->Planes[0])
  617.         {
  618.             /* If the Bitmap has got more than 1 Bitplane the construct below will
  619.                compute the other Bitplane addresses and stores them into the Bitmap
  620.             */
  621.             a = (unsigned int) FakeBM->Planes[0];    /* Address allocated memory, bitplane[0] already set! */
  622.             for (i = 1; i < FakeBM->Depth; i++)        /* Do it for the others (?) */
  623.             {
  624.                 a += FakeBM->BytesPerRow * FakeBM->Rows;    /* Plus size of one, single bitplane */
  625.                 FakeBM->Planes[i] = (PLANEPTR) a;            /* Store computed address */
  626.             }
  627.  
  628.             /* Figure out if user wishes only to dump the marked area */
  629.             if (PsMsg->pm_BlockStart)
  630.             {
  631.                 curr = PsMsg->pm_BlockStart;
  632.                 end = PsMsg->pm_BlockEnd;
  633.             }
  634.             else    /* No marked area, so take whole archive */
  635.             {
  636.                 curr = PsMsg->pm_TextStart;
  637.                 end = PsMsg->pm_TextEnd;
  638.             }
  639.  
  640.             /* How many lines are in the archive/text block ? */
  641.             a = 1;
  642.             while (curr < end && *curr != 0)
  643.                 if (*curr++ == 10)    /* Count linefeeds */
  644.                     a++;
  645.             Lines2Dump = a;        /* Remember for later */
  646.  
  647.             /* How many lines can be displayed per printer page? */
  648.             i = PD->pd_Preferences.PaperLength;        /* Lines per page */
  649.  
  650.             /* How many lines can be displayed per inch */
  651.             if (PD->pd_Preferences.PrintSpacing)
  652.                 r = 8
  653.                     else
  654.                 r = 6;
  655.  
  656.             /* How many dots can be printed out to one page in vertical direction? */
  657.             i = i * PED->ped_YDotsInch / r;        /* e.g. 66 lines * 180 dpi / 6 lines per page */
  658.  
  659.             /* How many pages required to print out those lines? */
  660.             p = a * PIO->IoDpRP.io_DestRows / i;
  661.             if (!p)
  662.                 p = 1;    /* At least one page! */
  663.  
  664.             /* Check if there is a rest of lines that need an extra page,
  665.                e.g. 60 lines per page , 153 lines to print but only 2 pages computed!
  666.             */
  667.             if (a > p * i / PIO->IoDpRP.io_DestRows)
  668.                 p ++;
  669.  
  670.             /* Give the user the chance to abort printing... */
  671.             SPrintf( TextBuffer, GStr( "\001\003Sure to print?\n\nPrintout would require %ld pages!"), p);
  672.             p = PsMsg->pm_CaseTell( TextBuffer);
  673.             if (p)
  674.             {
  675.                 /*
  676.                     'i' contains vertical dots per page, e.g. 1920,
  677.                     'a' contains amount lines to print
  678.                     'PIO->IoDpRP.io_DestCols' contains horizontal dots for a single line to print
  679.                     'PIO->IoDpRP.io_DestRows' contains vertical dots for a single line to print
  680.                 */
  681.                 VDotsPage = i;
  682.                 VDotsLine = PIO->IoDpRP.io_DestRows;
  683.                 HDotsLine = PIO->IoDpRP.io_DestCols;
  684.                 Lines     = a;
  685.                 CurrYdot = 0;    /* Imagine we're at the top of a page */
  686.                 CurrLine = 0;    /* No lines printed (yet) */
  687.  
  688.                 CM = GetColorMap( 2);    /* Monochrome - only two colours */
  689.                 if (CM)
  690.                 {
  691.                     SetRGB4CM( CM, 0, 0xF, 0xF, 0xF);    /* Background = white */
  692.                     SetRGB4CM( CM, 1, 0x0, 0x0, 0x0);    /* Foreground = black */
  693.  
  694.                     /* Establish this colour-map for dump */
  695.                     PIO->IoDpRP.io_ColorMap = CM;
  696.  
  697.                     /* We really want to print! */
  698.                     PIO->IoDpRP.io_Special &= ~SPECIAL_NOPRINT;
  699.  
  700.                     SetDrMd( FakeRP, JAM2);        /* We want to overwrite */
  701.                     SetAPen( FakeRP, 1);        /* Foreground pen */
  702.                     SetBPen( FakeRP, 0);        /* Background pen */
  703.  
  704.                     PB = PsMsg->pm_CreateProgressBar( GStr( "\002\001DAC Dumper"), \
  705.                                                       GStr( "\000\x42\Printout completed to "), \
  706.                                                       GStr( "\000\x43Pause/Continue"), GStr( "\000\x44\Continue"), \
  707.                                                       GStr( "\000\x45\Abandon") );
  708.  
  709.                     /* Continue even the progress-bar has not been attached to Dump */
  710.                     if (PsMsg->pm_BlockStart)
  711.                         PsMsg->pm_DumpStrings( FakeRP, &DumpCode, PsMsg->pm_BlockStart, PsMsg->pm_BlockEnd);
  712.                             else
  713.                         PsMsg->pm_DumpStrings( FakeRP, &DumpCode, PsMsg->pm_TextStart, PsMsg->pm_TextEnd);
  714.  
  715.                     if (PB)
  716.                         PsMsg->pm_FreeProgressBar( PB);
  717.  
  718. /*    REMOVED - since it should be clear...
  719.                     PsMsg->pm_Tell( GStr( "\002\004Print-job done.") ); */
  720.  
  721.                     FreeColorMap( CM);
  722.                 }
  723.                 else
  724.                     PsMsg->pm_Tell( GStr( "\000\x19\Cannot create unicoloured colour-map!") );
  725.             }
  726.             FreeMem( FakeBM->Planes[0], FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth);
  727.         }
  728.         else
  729.             PsMsg->pm_Tell( GStr( "\000\x1AUnable to get RAM for printout!") );
  730.     }
  731.     else
  732.         PsMsg->pm_Tell( GStr( "\000\x1BPrint-job aborted...") );
  733.  
  734. }
  735.  
  736.  
  737. /* ###############################################################
  738.     Here we go...
  739. */
  740.  
  741. void main( void)
  742. {
  743.     struct ViewPort *vp;
  744.     int a, i, p, l;
  745.  
  746.     /* Discover if we have been launched by Workbench */
  747.     if ( !WBenchMsg)
  748.         return;
  749.  
  750.     /* Either from Workbench or BareED */
  751.     if ( strcmp( WBenchMsg->sm_Message.mn_Node.ln_Name, "BAREED") != NULL)
  752.          return;
  753.  
  754.     /* Was BareED, so convert pointer to the message */
  755.     PsMsg = (struct PseudoMsg *) WBenchMsg;
  756.  
  757.     GfxBase = PsMsg->pm_GfxBase;
  758.     IntuitionBase = (struct IntuitionBase *) PsMsg->pm_IntuitionBase;
  759.     LocaleBase = PsMsg->pm_LocaleBase;
  760.     GadToolsBase = PsMsg->pm_GadToolsBase;
  761.  
  762.     OpenTheCatalog();
  763.  
  764.     TextBuffer = (STRPTR) AllocMem( TEXTBUFFERSIZE, MEMF_CLEAR);
  765.     FakeRP = (struct RastPort *) AllocMem( sizeof( struct RastPort), MEMF_CLEAR);
  766.     FakeBM = (struct BitMap *) AllocMem( sizeof( struct BitMap), MEMF_CLEAR);
  767.  
  768.     if (TextBuffer && FakeRP && FakeBM)
  769.     {
  770.         /* Create non-public message port */
  771.         if ( (PrinterPort = CreateMsgPort()) )
  772.         {
  773.             /* Allocate PrinterIO - for easier access as union */
  774.             if ( (PIO = (union PrinterIO *) CreateExtIO( PrinterPort, sizeof( union PrinterIO))) )
  775.             {
  776.                 /* Open the printer.device */
  777.                 if ( !(OpenDevice( "printer.device", 0, (struct IORequest *) PIO, 0)) )
  778.                 {
  779.                     PD = (struct PrinterData *) PIO->IoDpRP.io_Device;
  780.                     PED = (struct PrinterExtendedData *) &PD->pd_SegmentData->ps_PED;
  781.  
  782.                     vp = &(PsMsg->pm_EdWindow->WScreen->ViewPort);
  783.  
  784.                     /* Get the mode-id to compute correct aspect ratio */
  785.                     if ( (ModeID = GetVPModeID( vp)) != INVALID_ID)
  786.                     {
  787.                         /*    Create a faked Raster Port so that a BAD DIMENSION error is nearly impossible!
  788.                             To do this:
  789.                                 Tell the "printer.device" that the faked Bitmap is in horizontal direction
  790.                                 ten times larger than screen's! Could also be done with a fixed-width size,
  791.                                 e. g. 16000.
  792.                             Since no rendering is performed, we can play with empty bitplanes!
  793.                         */
  794.  
  795.                         /* Duplicate Raster Port - a bad hack? */
  796.                         CopyMem( PsMsg->pm_EdWindow->RPort, FakeRP, sizeof( struct RastPort));
  797.                         FakeRP->Layer = 0;
  798.                         FakeRP->BitMap = FakeBM;
  799.                         FakeBM->BytesPerRow = PsMsg->pm_EdWindow->WScreen->Width * 10 / 8;
  800.                         FakeBM->Rows = PsMsg->pm_EdWindow->WScreen->Height;
  801.                         FakeBM->Depth = 1;
  802.  
  803.                         /* Fill in parts of the IODRPRequest - used to compute correct aspect ratio */
  804.                         PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  805.                         PIO->IoDpRP.io_RastPort = FakeRP;
  806.                         PIO->IoDpRP.io_ColorMap = vp->ColorMap;
  807.                         PIO->IoDpRP.io_Modes = ModeID;
  808.                         PIO->IoDpRP.io_SrcX = 0;
  809.                         PIO->IoDpRP.io_SrcY = 0;
  810.  
  811.                         /* We need a valid right margin to compute and lay out strings! */
  812.                         while (PsMsg->pm_RightMargin == NULL)
  813.                             PsMsg->pm_RightMargin = PsMsg->pm_RequestNumber( 0, GStr( "\002\001DAC Dumper"),\
  814.                                                                                 GStr( "\002\002Enter right margin!"),\
  815.                                                                                 GStr( "\002\003Okay"), 0);
  816.  
  817.                         /* How long is a line in pixels? */
  818.                         PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  819.  
  820.                         /* How high is the font (plus one because BareED reserves between each text line a row! */ 
  821.                         PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  822.  
  823.                         /* We don't want to print, but we want to know the correct dimension */
  824.                         PIO->IoDpRP.io_Special = SPECIAL_ASPECT|SPECIAL_NOFORMFEED|SPECIAL_TRUSTME|SPECIAL_NOPRINT;
  825.  
  826.                         /* Initialise with zero so "printer device" calculates dump dimension! */
  827.                         PIO->IoDpRP.io_DestCols = 0;
  828.                         PIO->IoDpRP.io_DestRows = 0;
  829.  
  830.                         /* Ask for dimension */
  831.                         DoIO( (struct IORequest *) PIO);
  832.  
  833.                         if (PIO->IoDpRP.io_Error == 0)
  834.                         {
  835.                             DestHDots = p = PIO->IoDpRP.io_DestCols;    /* Dots in horizontal direction
  836.                                                                            (to fit line fulfilled onto paper) */
  837.                             DestVDots = l = PIO->IoDpRP.io_DestRows;    /* Dots in vertical direction (height of
  838.                                                                             one single line!) */
  839.                         }
  840.                         else
  841.                         {
  842.                             a = PIO->IoDpRP.io_Error;
  843.                             if (a < 0)
  844.                                 a = a * -1 + 7;
  845.  
  846.                             SPrintf( TextBuffer, GStr( "\000\x18\Error: %s"), GStr( ErrorText[a]));
  847.                             PsMsg->pm_Tell( TextBuffer);                                    
  848.                         }
  849.  
  850.                         /* Do not continue upon error */
  851.                         if ( !PIO->IoDpRP.io_Error)
  852.                         {
  853.                             /* How wide is a string basing on RightMargin (in pixels -
  854.                                as limit for WidestStrLen()) ?
  855.                             */
  856.                             a = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  857.  
  858.                             /* Get the height of the font and care about the row that BareED reserves
  859.                                between each text line
  860.                             */
  861.                             i = PsMsg->pm_Font->tf_YSize + 1;
  862.  
  863.                             SPrintf( TextBuffer, GStr( "\000\x40\Dimension when using a right margin of %ld" \
  864.                                                        " characters:\n\nline length = %4ld pixles = X-dots = %4ld\n" \
  865.                                                        "line height = %4ld pixels = Y-dots = %4ld"), \
  866.                                                         PsMsg->pm_RightMargin, a, p, i, l);
  867.                             PsMsg->pm_Tell( TextBuffer);
  868.  
  869.                             /* Invoke function WidestStrLen() with a set CallBack-Hook */ 
  870.                             if (PsMsg->pm_BlockStart)
  871.                                 p = PsMsg->pm_WidestStrLen( PsMsg->pm_BlockStart, PsMsg->pm_BlockEnd,\
  872.                                                             &InformCode, a);
  873.                                     else
  874.                                 p = PsMsg->pm_WidestStrLen( PsMsg->pm_TextStart, PsMsg->pm_TextEnd,\
  875.                                                             &InformCode, a);
  876.  
  877.                             /* Did the user abandoned computing? */
  878.                             if (Continue)
  879.                             {
  880.                                 /* No... */
  881.                                 l = p / PsMsg->pm_CharSpace[ (UBYTE) 32];
  882.                                 if ( l * PsMsg->pm_CharSpace[ (UBYTE) 32] < p)    /* Correct number of chars! */
  883.                                     l ++;
  884.  
  885.                                 SPrintf( TextBuffer, GStr( "\000\x41Widest line: %ld pixels or %ld characters!"), p, l);
  886.                                 PsMsg->pm_Tell( TextBuffer);
  887.  
  888.  
  889.                                 /* Now, compute X-offset for printout. Take "Printer-Prefs" left margin - not
  890.                                    "PrinterGfx-Prefs" settings!
  891.                                 */
  892.                                 i = PD->pd_Preferences.PrintXOffset;        /* Remember to restore later */
  893.  
  894.                                 l = PD->pd_Preferences.PrintSpacing >> 10;    /* Get used printer's font */
  895.                                 if (l == 0)
  896.                                     l = 10;    /* Pica 10 cpi */
  897.                                 if (l == 1)
  898.                                     l = 12;    /* Elite 12 cpi */
  899.                                 if (l == 2)
  900.                                     l = 17;    /* Fine 15/17 cpi */
  901.  
  902.                                 /* E. g.: 30 (left margin) * 10 / 10 (Pica = 10 cpi) = 30(/10ths inch) */
  903.                                 PD->pd_Preferences.PrintXOffset = PD->pd_Preferences.PrintLeftMargin * 10 / l;
  904.  
  905.                                 /* Print out graphic */
  906.                                 DoTheDump( p);
  907.  
  908.                                 PD->pd_Preferences.PrintXOffset = i;
  909.                             }
  910.                         }
  911.                     }
  912.                     else
  913.                         PsMsg->pm_Tell( GStr( "\000\x1CInvalid screen-mode-ID") );
  914.  
  915.                     CloseDevice( (struct IORequest *) PIO);
  916.                 }
  917.                 else
  918.                     PsMsg->pm_Tell( GStr( "\000\x1D\Cannot open the \"printer device\"") );
  919.  
  920.                 DeleteExtIO( (struct IORequest *) PIO);
  921.  
  922.             }
  923.             else
  924.                 PsMsg->pm_Tell( GStr( "\000\x1E\Cannot create required I/O-request") );
  925.  
  926.             DeleteMsgPort( PrinterPort);
  927.  
  928.         }
  929.         else
  930.             PsMsg->pm_Tell( GStr( "\000\x1F\Cannot create a message port") );
  931.  
  932.     }
  933.  
  934.     if (FakeBM)
  935.         FreeMem( FakeBM, sizeof( struct BitMap));
  936.     if (FakeRP)
  937.         FreeMem( FakeRP, sizeof( struct RastPort));
  938.     if (TextBuffer)
  939.         FreeMem( TextBuffer, TEXTBUFFERSIZE);
  940.  
  941.     CloseTheCatalog();
  942. }
  943.  
  944. /*
  945.     This is the end of DAC-Dump - if you can do better than me - feel free to modify.
  946. */